package com.thread.threadfirst.studyThread4;

import java.util.concurrent.*;

/**
 * 6、future
 * FutureTask 未来任务，即该任务的返回值在以后才能拿到。
 */
public class T_FutureTask {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> task = new FutureTask(() -> {  //FutureTask可以包装一个Callable类型的任务，Callable的返回值是个泛型"V"，而Callable包装成一个任务时 得要指定返回值的类型，
            // 所以通过FutureTask<Integer>来指定，显然该任务的返回值是Integer类型的。相当于一个Callable的任务封装成FutureTask。
            //此处为什么要包装呢 因为Thread启动时不能直接扔Callable类型的任务（因为Callable有返回值）只能扔Task，而且Callable也没有get()来阻塞着等待结果。
            TimeUnit.MILLISECONDS.sleep(500);
            return 1000;
        });

        new Thread(task).start();

        System.out.println(task.get());  //阻塞，一直等到任务执行完 拿到返回值。所以FutureTask关键的是get()方法，而且此get()是对于返回值的阻塞，与之前的BlockingQueue针对于容器的存放获取的阻塞不同。
        //*************************************************
        ExecutorService service = Executors.newFixedThreadPool(5);  //产生固定数量为5的线程池 即5个线程
        Future<Integer> f = service.submit(() -> {  //submit()是可以放Callable类型的任务的，任务的返回值放到Future中 不是FutureTask了，因为submit()中已经new了一个FutureTask扔到里面去，然后返回值就放到Future中 指定Integer类型。
            TimeUnit.MILLISECONDS.sleep(500);
            return 1;
        });

        System.out.println(f.get());  //注意：这里如果注释掉，下面的isDone()会输出false，因为上面的子线程启动了，还没等子线程执行完 接下来主线程就输出isDone() 肯定是false。
        //但如果没有注释掉，就会先等待着获取到返回值，然后才执行下面的 所有会是true。
        System.out.println(f.isDone());  //isDone()：任务是否执行完。如果上面的get()没有注释掉，就会先等待着获取到返回值，然后才执行到这里 所以会是true。
//        service.shutdown();  //注意：没有此shutdown() 就还有线程在 idea就不能关闭，有了它，线程消失了 idea才能关闭。
    }
}
